//============================================================================
// Name        : cpp_memory.cpp
// Author      : darkflash
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

// getTotal
#include <sstream>

// method1 & method2
#include <unistd.h>

// method1
#include <ios>
#include <iostream>
#include <fstream>
#include <string>

// method2
#include <sys/resource.h>

using namespace std;

void process_mem_usage(double& vm_usage, double& resident_set)
{
   using std::ios_base;
   using std::ifstream;
   using std::string;

   vm_usage     = 0.0;
   resident_set = 0.0;

   // 'file' stat seems to give the most reliable results
   //
   ifstream stat_stream("/proc/self/stat",ios_base::in);

   // dummy vars for leading entries in stat that we don't care about
   //
   string pid, comm, state, ppid, pgrp, session, tty_nr;
   string tpgid, flags, minflt, cminflt, majflt, cmajflt;
   string utime, stime, cutime, cstime, priority, nice;
   string O, itrealvalue, starttime;

   // the two fields we want
   //
   unsigned long vsize;
   long rss;

   stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
               >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
               >> utime >> stime >> cutime >> cstime >> priority >> nice
               >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest

   stat_stream.close();

   long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
   vm_usage     = vsize / 1024.0;
   resident_set = rss * page_size_kb;
}

/**
 * Returns the peak (maximum so far) resident set size (physical
 * memory use) measured in bytes, or zero if the value cannot be
 * determined on this OS.
 */
size_t getPeakRSS( )
{
    /* BSD, Linux, and OSX -------------------------------------- */
    struct rusage rusage;
    getrusage( RUSAGE_SELF, &rusage );
    return (size_t)(rusage.ru_maxrss * 1024L);
}

/**
 * Returns the current resident set size (physical memory use) measured
 * in bytes, or zero if the value cannot be determined on this OS.
 */
size_t getCurrentRSS( )
{
    /* Linux ---------------------------------------------------- */
    long rss = 0L;
    FILE* fp = NULL;
    if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
        return (size_t)0L;      /* Can't open? */
    if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
    {
        fclose( fp );
        return (size_t)0L;      /* Can't read? */
    }
    fclose( fp );
    return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
}

string getTotalMemory()
{
    FILE* stream = popen( "head -n1 /proc/meminfo", "r" );
    ostringstream output;
    int bufsize = 128;

    while( !feof( stream ) && !ferror( stream ))
    {
        char buf[bufsize];
        int bytesRead = fread( buf, 1, bufsize, stream );
        output.write( buf, bytesRead );
    }
    string result = output.str();

    string label, ram;
    istringstream iss(result);
    iss >> label;
    iss >> ram;

    return ram;
}

int main() {
	// total
	cout << "total: " << getTotalMemory() << endl;

	// method1
	cout << "=========> method1" << endl;

	double vm, rss;
	process_mem_usage(vm, rss);
	cout << "VM: " << vm << "; RSS: " << rss << endl;

	// method2
	cout << "=========> method2" << endl;
	size_t peekRSS = getPeakRSS();
	size_t currentRSS = getCurrentRSS();

	cout << "peekRSS: " << peekRSS << endl;
	cout << "currentRSS: " << currentRSS << endl;



	return 0;
}
